package com.clg.common.jqueryDataTables;

import com.clg.common.beans.KeyValue;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.TableMapping;
import org.apache.commons.lang.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.*;

/**
 * Created by usercai on 2016/10/14.
 */
public class DataTablesUtil {
    /**
     * 将jqueryDataTables请求转换成对象
     * @param request
     * @return
     */
    public static DataTablesParam getParam(HttpServletRequest request)
    {
        if(request.getParameter("sEcho")!=null && request.getParameter("sEcho")!= "")
        {

            DataTablesParam param = new DataTablesParam();
            param.sEcho = request.getParameter("sEcho");
            param.sSearch = request.getParameter("sSearch");
            param.sColumns = request.getParameter("sColumns");
            param.iDisplayStart = Integer.parseInt( request.getParameter("iDisplayStart") );
            param.iDisplayLength = Integer.parseInt( request.getParameter("iDisplayLength") );
            param.iColumns = Integer.parseInt( request.getParameter("iColumns") );

            //组装columns
            DataTablesParamSearch[] columnSearchs = new DataTablesParamSearch[param.iColumns];
            Enumeration<String> paramNames = request.getParameterNames();

            //sort define: {0:desc,...}
            List<KeyValue> sortIndexDirs = new ArrayList();
            while (paramNames.hasMoreElements()){
                String name = paramNames.nextElement();
                if(name.matches("mDataProp_\\d+")){
                    int index = Integer.parseInt(name.replace("mDataProp_",""));
                    DataTablesParamSearch columnSearch = columnSearchs[index];
                    if(columnSearch==null){
                        columnSearch = new DataTablesParamSearch();
                        columnSearchs[index] = columnSearch;
                    }
                    columnSearch.mDataProp=request.getParameter(name);
                }
                if(name.matches("sSearch_\\d+")){
                    int index = Integer.parseInt(name.replace("sSearch_",""));
                    DataTablesParamSearch columnSearch = columnSearchs[index];
                    if(columnSearch==null){
                        columnSearch = new DataTablesParamSearch();
                        columnSearchs[index] = columnSearch;
                    }
                    columnSearch.sSearch=request.getParameter(name);
                }
                if(name.matches("bRegex_\\d+")){
                    int index = Integer.parseInt(name.replace("bRegex_",""));
                    DataTablesParamSearch columnSearch = columnSearchs[index];
                    if(columnSearch==null){
                        columnSearch = new DataTablesParamSearch();
                        columnSearchs[index] = columnSearch;
                    }
                    columnSearch.bRegex= Boolean.parseBoolean(request.getParameter(name));
                }
                if(name.matches("bSearchable_\\d+")){
                    int index = Integer.parseInt(name.replace("bSearchable_",""));
                    DataTablesParamSearch columnSearch = columnSearchs[index];
                    if(columnSearch==null){
                        columnSearch = new DataTablesParamSearch();
                        columnSearchs[index] = columnSearch;
                    }
                    columnSearch.bSearchable=Boolean.parseBoolean(request.getParameter(name));
                }
                if(name.matches("bSortable_\\d+")){
                    int index = Integer.parseInt(name.replace("bSortable_",""));
                    DataTablesParamSearch columnSearch = columnSearchs[index];
                    if(columnSearch==null){
                        columnSearch = new DataTablesParamSearch();
                        columnSearchs[index] = columnSearch;
                    }
                    columnSearch.bSortable=Boolean.parseBoolean(request.getParameter(name));
                }

                //sort
                if(name.matches("iSortCol_\\d+")){
                    int index = Integer.parseInt(name.replace("iSortCol_",""));
                    String sortDir = request.getParameter("sSortDir_"+index);
                    String columnIndex = request.getParameter(name);
                    sortIndexDirs.add(new KeyValue(columnIndex,sortDir));
                }
            }
            for(KeyValue sortIndexDir:sortIndexDirs){
                DataTablesParamSearch columnSearch = columnSearchs[Integer.parseInt(sortIndexDir.getKey())];
                columnSearch.isSort = true;
                columnSearch.sSortDir = sortIndexDir.getValue().toString();
            }

            param.paramSearch = Arrays.asList(columnSearchs);
            return param;
        }else
            return null;
    }

    /**
     * jquery dataTables 分页查询
     * @param req
     * @param dao
     * @param <T>
     * @return
     */
    public static <T extends Model> DataTablesResult queryPage(DataTablesParam req, T dao){
        String sql = "from "+getTableName(dao);
        List<Object> params = new ArrayList();

        if(req.paramSearch!=null){
            //search
            StringBuffer querySql = new StringBuffer("");
            if(StringUtils.isNotBlank(req.sSearch)) {
                for (DataTablesParamSearch s : req.paramSearch) {
                    if (s.bSearchable && StringUtils.isNotBlank(s.mDataProp)) {
                        querySql.append(" or " + s.mDataProp + " like ?");
                        params.add("%" + req.sSearch + "%");
                    }
                }
            }
            if(querySql.length()>0){
                querySql.delete(0,3);
                querySql.insert(0," where ");
                sql += querySql.toString();
            }

            //order by
            StringBuffer orderBy = new StringBuffer("");
            for(DataTablesParamSearch s:req.paramSearch){
                if(s.isSort && StringUtils.isNotBlank(s.mDataProp)){
                    orderBy.append(s.mDataProp+" "+s.sSortDir+",");
                }
            }
            if(orderBy.length()>0){
                orderBy.delete(orderBy.length()-1,orderBy.length());
                orderBy.insert(0," order by ");
                sql += orderBy.toString();
            }
        }
        //没有条件时的总条数
        long totalRows = Db.queryLong("select count(*) from "+getTableName(dao));
        return fromPage(req.sEcho, totalRows, dao.paginate(req.getCurtPageNum(),req.iDisplayLength,"select *",sql.toString(),params.toArray()));
    }

    /**
     * jfinal page对象转换成jquery dataTables接受对象
     * @param sEcho
     * @param page
     * @return
     */
    public static DataTablesResult fromPage(String sEcho,long total,Page page){
        DataTablesResult result = new DataTablesResult();
        result.setsEcho(sEcho);
        result.setiTotalRecords(total); //未使用过滤的条数
        result.setiTotalDisplayRecords(page.getTotalRow());

        /*List<Map<String,Object>> datas = new ArrayList();
        List<Model> queryDatas = (List<Model>)page.getList();
        if(queryDatas!=null&&queryDatas.size()!=0){
            //获取bean的get方法，得到值，转json时不用数据库的列定义，而是类方法属性名称
            List<KeyValue> methodAttrs = new ArrayList();
            Method[] methods = queryDatas.get(0).getClass().getMethods();
            for (Method method : methods) {
                String methodName = method.getName();
                if (methodName.startsWith("get") == false || methodName.length() <= 3) {	// only setter method
                    continue;
                }
                if(methodName.equals("getClass")) continue;
                Class<?>[] types = method.getParameterTypes();
                if (types.length != 0) {						// only one parameter
                    continue;
                }
                String attrName = StrKit.firstCharToLowerCase(methodName.substring(3));
                methodAttrs.add(new KeyValue(attrName,method));
            }

            for(Model m:queryDatas){
                Map<String,Object> data = new HashMap();
                for(KeyValue getAttr:methodAttrs){
                    try {
                        data.put(getAttr.getKey(), ((Method) getAttr.getValue()).invoke(m));
                    }
                    catch(Exception e){
                        throw new RuntimeException(e);
                    }
                }
                datas.add(data);
            }
        }
        result.setAaData(datas);*/

        result.setAaData(page.getList());
        return result;
    }

    private static String getTableName(Model dao){
        Class c = dao.getClass();
        c = c.getName().indexOf("EnhancerByCGLIB") == -1 ? c : c.getSuperclass();
        return TableMapping.me().getTable(c).getName();
    }
}
